package me.zhengjie.modules.system.rest

import io.swagger.v3.oas.annotations.media.Schema
import jakarta.servlet.http.HttpServletResponse
import me.zhengjie.common.exception.BadRequestException
import me.zhengjie.common.utils.*
import me.zhengjie.logging.annotation.Log
import me.zhengjie.modules.system.domain.*
import me.zhengjie.modules.system.domain.vo.MenuVo
import me.zhengjie.modules.system.service.MenuService
import me.zhengjie.modules.system.service.RoleService
import me.zhengjie.modules.system.service.UserService
import me.zhengjie.modules.system.service.dto.MenuDTO
import me.zhengjie.modules.system.service.dto.MenuQueryCriteria
import me.zhengjie.modules.system.service.mapper.MenuMapper
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import java.io.IOException

/**
 * @author Kuki Wu
 * @date 2018-12-03
 */
@Schema(description = "系统：菜单管理")
@RestController
@RequestMapping("/api/menus")
class MenuController(
    private val menuService: MenuService,
    private val menuMapper: MenuMapper,
    private val userService: UserService,
    private val roleService: RoleService,
) {

    companion object {
        const val ENTITY_NAME = "menu"
    }

    @Log("导出菜单数据")
    @Schema(description = "导出菜单数据")
    @GetMapping(value = ["/download"])
    @PreAuthorize("@el.check('menu:list')")
    @Throws(
        IOException::class
    )
    fun download(response: HttpServletResponse?, criteria: MenuQueryCriteria?) {
        menuService.download(menuService.queryAll(criteria!!, false) as MutableList<MenuDTO>, response)
    }

    @GetMapping(value = ["/build"])
    @Schema(description = "获取前端所需菜单")
    fun buildMenus(): ResponseEntity<List<MenuVo?>?>? {
        val menuDtoList: List<MenuDTO?>? = menuService.findByUser(SecurityUtils.userId)
        val menus: List<MenuDTO?>? = menuService.buildTree(menuDtoList)
        return ResponseEntity(menuService.buildMenus(menus!!), HttpStatus.OK)
    }

    @Schema(description = "返回全部的菜单")
    @GetMapping(value = ["/lazy"])
    @PreAuthorize("@el.check('menu:list','roles:list')")
    fun queryAllMenu(@RequestParam pid: Long?): ResponseEntity<List<MenuDTO?>?>? {
        return ResponseEntity(menuService.getMenus(pid), HttpStatus.OK)
    }
//    @Schema(description = "获取前端所需菜单")
//    @GetMapping(value = ["/build"])
//    fun buildMenus(): ResponseEntity<*> {
//        val user = userService.findByName(SecurityUtils.username)
//        val menuDTOList = menuService.findByRoles(roleService.findByUsersId(user!!.id!!) as MutableList<RoleSmallDTO>)
//        val menuDTOS = menuService.buildTree(menuDTOList)["content"] as List<MenuDTO>?
//        return ResponseEntity(menuService.buildMenus(menuDTOS!!), HttpStatus.OK)
//    }

//    @get:PreAuthorize("@el.check('menu:list','roles:list')")
//    @get:GetMapping(value = ["/tree"])
//    @get:Schema(description = "返回全部的菜单")
//    val menuTree: ResponseEntity<*>
//        get() = ResponseEntity(menuService.getMenuTree(menuService.findByPid(0L)!!), HttpStatus.OK)

    @Schema(description = "根据菜单ID返回所有子节点ID，包含自身ID")
    @GetMapping(value = ["/child"])
    @PreAuthorize("@el.check('menu:list','roles:list')")
    fun childMenu(@RequestParam id: Long?): ResponseEntity<Any?>? {
        val menuSet = HashSet<Menu>()
        val menuList = menuService.getMenus(id)
        menuSet.add(menuService.findOne(id!!))
        val updatedMenuSet = menuService.getChildMenus(menuMapper.toEntity(menuList as List<MenuDTO?>) as MutableList<Menu?>, menuSet as MutableList<Menu?>)
        val ids = updatedMenuSet!!.map { it!!.id }.toSet()
        return ResponseEntity(ids, HttpStatus.OK)
    }

//    @Log("查询菜单")
//    @Schema(description = "查询菜单")
//    @GetMapping
//    @PreAuthorize("@el.check('menu:list')")
//    fun getMenus(criteria: MenuQueryCriteria?): ResponseEntity<*> {
//        val menuDTOList = menuService.queryAll(criteria!!, true)
//        return ResponseEntity(menuService.buildTree(menuDTOList as MutableList<MenuDTO>), HttpStatus.OK)
//    }

    @GetMapping
    @Schema(description = "查询菜单")
    @PreAuthorize("@el.check('menu:list')")
    @Throws(Exception::class)
    fun queryMenu(criteria: MenuQueryCriteria?): ResponseEntity<PageResult<MenuDTO?>?>? {
        val menuDtoList: List<MenuDTO?>? = menuService.queryAll(criteria!!, true)
        return ResponseEntity(PageUtil.toPage(menuDtoList, menuDtoList!!.size.toLong()), HttpStatus.OK)
    }

    @Schema(description ="查询菜单:根据ID获取同级与上级数据")
    @PostMapping("/superior")
    @PreAuthorize("@el.check('menu:list')")
    fun getMenuSuperior(@RequestBody ids: List<Long>): ResponseEntity<List<MenuDTO>> {
        val menuDtos = LinkedHashSet<MenuDTO>()
        if (ids.isNotEmpty()) {
            for (id in ids) {
                val menuDto = menuService.findById(id)
                val menuDtoList = menuService.getSuperior(menuDto, mutableListOf())
                for (menu in menuDtoList!!) {
                    if (menu!!.id == menuDto!!.pid) {
                        menu.subCount = menu.subCount!! - 1
                    }
                }
                menuDtos.addAll(menuDtoList.map { it!! })
            }
            // 编辑菜单时不显示自己以及自己下级的数据，避免出现PID数据环形问题
            val filteredMenuDtos = menuDtos.filter { !ids.contains(it.id) }.toSet()
            return ResponseEntity(menuService.buildTree(filteredMenuDtos.toList()), HttpStatus.OK) as  ResponseEntity<List<MenuDTO>>
        }
        return ResponseEntity(menuService.getMenus(null), HttpStatus.OK) as ResponseEntity<List<MenuDTO>>
    }

    @Log("新增菜单")
    @Schema(description = "新增菜单")
    @PostMapping
    @PreAuthorize("@el.check('menu:add')")
    fun createMenu(@Validated @RequestBody resources: Menu): ResponseEntity<*> {
        if (resources.id != null) {
            throw BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID")
        }
        return ResponseEntity(menuService.create(resources), HttpStatus.CREATED)
    }


    @Log("修改菜单")
    @Schema(description = "修改菜单")
    @PutMapping
    @PreAuthorize("@el.check('menu:edit')")
    fun update(
        @Validated(
            Menu.Update::class
        ) @RequestBody resources: Menu?
    ): ResponseEntity<*> {
        menuService.update(resources!!)
        return ResponseEntity<Any?>(HttpStatus.NO_CONTENT)
    }

//    @Log("删除菜单")
//    @Schema(description = "删除菜单")
//    @DeleteMapping(value = ["/{id}"])
//    @PreAuthorize("@el.check('menu:del')")
//    fun delete(@PathVariable id: Long?): ResponseEntity<*> {
//        val menuList = menuService.findByPid(id!!)
//        var menuSet: MutableSet<Menu> = HashSet()
//        menuSet.add(menuService.findOne(id))
//        menuSet = menuService.getDeleteMenus(menuList, menuSet) as MutableSet<Menu>
//        menuService.delete(menuSet)
//        return ResponseEntity<Any?>(HttpStatus.OK)
//    }

    @Log("删除菜单")
    @Schema(description = "删除菜单")
    @DeleteMapping
    @PreAuthorize("@el.check('menu:del')")
    fun deleteMenu(@RequestBody ids: Set<Long?>): ResponseEntity<Any?>? {
        var menuSet: MutableSet<Menu?>? = hashSetOf()
        for (id in ids) {
            val menuList: List<MenuDTO?>? = menuService.getMenus(id)
            menuSet!!.add(menuService.findOne(id!!))
            menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList as List<MenuDTO?>) as MutableList<Menu?>, menuSet as MutableList<Menu?>) as MutableSet<Menu?>
        }
        menuService.delete(menuSet!! as Set<Menu>)
        return ResponseEntity(HttpStatus.OK)
    }
}